#include "server.hh"

# include "map/map.hh"
# include "network-error-handler-client.hh"

# include <tools/utility.hh>
# include <request/type.hh>
# include "request/request-client.hh"

# include <iostream>

Server::Server (const std::string& server, const std::string& port):
  run_ (true),
  ios_ (),
  nm_ (new tcp::socket (ios_), new RequestCreatorClient (), new NetworkErrorHandlerClient ()),
  objmap_ (),
  rh_ (&objmap_, &disp_, nm_),
  reset_selection_ (false)
{
  try
  {
    if (server == "localhost")
      nm_.s ()->connect (tcp::endpoint (tcp::v4 (), atoi (port.c_str ())));
    else
    {
      tcp::endpoint ep (boost::asio::ip::address::from_string (server), atoi (port.c_str ()));
      nm_.s ()->connect (ep);
    }
  }
  catch (std::exception& e)
  {
    std::cout << "ERROR server not found" << std::endl;
    exit (1);
  }
}

Server::~Server ()
{
  nm_.send (RType::DISCONNECTION, "");

  nm_.s ()->shutdown (tcp::socket::shutdown_both);
  nm_.s ()->close ();

  ios_.stop ();

  //  delete rts_map_;
  //  delete fps_map_;
  exit (1);
}

bool
Server::connect (const std::string& logpwd)
{
  std::cout << "Connecting to server..." << std::endl;
  nm_.send (RType::CONNECTION, logpwd);

  if (nm_.eh ()->error ())
    return false;

  std::cout << "Waiting for the server..." << std::endl;
  boost::shared_ptr<Request> rq = nm_.read ();

  if (nm_.eh ()->error ())
    return false;

  boost::shared_ptr<ConnectionClient> cc = boost::dynamic_pointer_cast<ConnectionClient> (rq);

  std::cout << cc->msg () << std::endl;

  if (cc->msg () != "OK")
    return false;

  return true;
}

void
Server::build_map ()
{
  boost::shared_ptr<Request> rq = nm_.read ();
  boost::shared_ptr<AskMapClient> amc = boost::dynamic_pointer_cast<AskMapClient> (rq);

  if (!amc.use_count ())
  {
    std::cout << "Error other request received while needing to build the map" << std::endl;
    assert (false);
  }

  (*amc) (&rh_);
  //  rts_map_ = rh_.rts_map ();
}

void
Server::run ()
{
  boost::shared_ptr<Request> rq;

  std::string tmp;
  nm_.send (RType::READY, tmp);
  while (!nm_.eh ()->error () && run_)
  {
    rq = nm_.read ();

    (*rq) (&rh_);
  }
}

const Map*
Server::map () const
{
  if (rh_.fps_map ())
    return rh_.fps_map ();

  return rh_.rts_map ();
}

void
Server::stop ()
{
  run_ = false;
  ((NetworkErrorHandlerClient*) nm_.eh ())->disconnecting (true);
}
